package com.finalterm.product.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.finalterm.common.result.Result;
import com.finalterm.product.dto.ProductCreateDTO;
import com.finalterm.product.dto.StockDeductDTO;
import com.finalterm.product.service.ProductCacheService;
import com.finalterm.product.service.ProductService;
import com.finalterm.product.vo.ProductVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

/**
 * 商品控制器
 */
@Slf4j
@RestController
@RequestMapping("/api/product")
@RequiredArgsConstructor
public class ProductController {

    private final ProductService productService;
    private final ProductCacheService productCacheService;
    
    /**
     * 创建商品
     */
    @PostMapping("/create")
    @SentinelResource(value = "product-create",
                     blockHandler = "createProductBlockHandler")  // 只处理流控规则
    public Result<ProductVO> createProduct(@Validated @RequestBody ProductCreateDTO createDTO) {
        ProductVO productVO = productService.createProduct(createDTO);
        return Result.success("商品创建成功", productVO);
    }
    
    /**
     * 获取商品详情
     */
    @GetMapping("/detail/{productId}")
    @SentinelResource(value = "product-detail",
                     fallback = "getProductDetailFallback",  // 处理业务异常
                     blockHandler = "getProductDetailBlockHandler")  // 只处理流控/熔断规则触发
    public Result<ProductVO> getProductDetail(@PathVariable Long productId,
                                            @RequestHeader(value = "X-User-Id", required = false) Long userId) {
        ProductVO productVO = productService.getProductDetail(productId, userId);
        return Result.success(productVO);
    }

    /**
     * 商品详情熔断/流控降级方法
     * 只在Sentinel规则触发时执行（流控、熔断等），普通业务异常不会执行此方法
     */
    public Result<ProductVO> getProductDetailBlockHandler(Long productId, Long userId, BlockException ex) {
        log.warn("商品详情触发Sentinel规则降级，productId: {}, 规则类型: {}, 异常: {}",
                productId, ex.getClass().getSimpleName(), ex.getMessage());

        // 返回缓存的默认商品信息
        ProductVO defaultProduct = productCacheService.getDefaultProduct(productId);
        return Result.success("系统保护机制触发，返回缓存商品信息", defaultProduct);
    }

    // getProductDetailFallback
    public Result<ProductVO> getProductDetailFallback(Long productId, Long userId, Throwable ex) {
        log.warn("商品详情触发业务异常降级，productId: {}, 异常: {}", productId, ex.getMessage());
        // 返回缓存的默认商品信息
        ProductVO defaultProduct = productCacheService.getDefaultProduct(productId);
        return Result.success("系统保护机制触发，返回缓存商品信息", defaultProduct);
    }
    
    /**
     * 分页查询商品列表
     */
    @GetMapping("/list")
    @SentinelResource(value = "product-list")
    public Result<Page<ProductVO>> getProductList(@RequestParam(defaultValue = "1") int page,
                                                @RequestParam(defaultValue = "10") int size,
                                                @RequestParam(required = false) String category) {
        Page<ProductVO> productPage = productService.getProductList(page, size, category);
        return Result.success(productPage);
    }
    
    /**
     * 扣减库存（内部调用）
     */
    @PostMapping("/stock/deduct")
    @SentinelResource(value = "product-stock-deduct",
                     blockHandler = "deductStockBlockHandler")  // 只处理流控规则
    public Result<Boolean> deductStock(@Validated @RequestBody StockDeductDTO deductDTO) {
        boolean success = productService.deductStock(deductDTO);
        return Result.success(success);
    }
    
    /**
     * 恢复库存（内部调用）
     */
    @PostMapping("/stock/recover")
    @SentinelResource(value = "product-stock-recover")
    public Result<Boolean> recoverStock(@RequestParam Long productId,
                                      @RequestParam Integer quantity,
                                      @RequestParam String orderId) {
        boolean success = productService.recoverStock(productId, quantity, orderId);
        return Result.success(success);
    }

    /**
     * 确认库存扣减（内部调用）
     */
    @PostMapping("/stock/confirm")
    @SentinelResource(value = "product-stock-confirm")
    public Result<Boolean> confirmStockDeduction(@RequestParam String orderNo,
                                                @RequestParam Long productId,
                                                @RequestParam Integer quantity,
                                                @RequestParam String orderStatus) {
        boolean success = productService.confirmStockDeduction(orderNo, productId, quantity, orderStatus);
        return Result.success(success);
    }
    
    /**
     * 更新商品信息
     */
    @PutMapping("/update/{productId}")
    @SentinelResource(value = "product-update")
    public Result<ProductVO> updateProduct(@PathVariable Long productId,
                                         @Validated @RequestBody ProductCreateDTO updateDTO) {
        ProductVO productVO = productService.updateProduct(productId, updateDTO);
        return Result.success("商品更新成功", productVO);
    }
    
    /**
     * 删除商品
     */
    @DeleteMapping("/delete/{productId}")
    @SentinelResource(value = "product-delete")
    public Result<Boolean> deleteProduct(@PathVariable Long productId) {
        boolean success = productService.deleteProduct(productId);
        return Result.success("商品删除成功", success);
    }

    // ==================== Sentinel BlockHandler 方法 ====================

    /**
     * 商品创建流控降级方法
     * 只在流控规则触发时执行，普通业务异常不会执行
     */
    public Result<ProductVO> createProductBlockHandler(ProductCreateDTO createDTO, BlockException ex) {
        log.warn("商品创建触发流控规则，限制访问频率，异常: {}", ex.getMessage());
        return Result.error("系统繁忙，请稍后重试创建商品");
    }

    /**
     * 库存扣减流控降级方法
     * 只在流控规则触发时执行，普通业务异常不会执行
     */
    public Result<Boolean> deductStockBlockHandler(StockDeductDTO deductDTO, BlockException ex) {
        log.warn("库存扣减触发流控规则，限制访问频率，异常: {}", ex.getMessage());
        return Result.error("系统繁忙，库存扣减失败，请稍后重试");
    }
}
